<?php  if (!defined('TL_ROOT')) die('You can not access this file directly!');

/**
 * Copyright (c) 2010, must art
 *All rights reserved.
 *
 *Redistribution and use in source and binary forms, with or without
 *modification, are permitted provided that the following conditions are met:
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *    * Neither the name of the <organization> nor the
 *      names of its contributors may be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 *
 *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 *ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 *WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *DISCLAIMED. IN NO EVENT SHALL must art BE LIABLE FOR ANY
 *DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * PHP version 5
 * @copyright  must art 2010
 * @author     Jan Philipp Pietrzyk <programming@must-art.de>
 * @package    
 * @license    BSD
 * @filesource
 */

class BackendMAYoutubeApiConnector extends Backend {
	/**
     * The Youtube Object, set in the login() method
     * @access protected
     * @var Zend_Gdata_Youtube
     */
	protected $yt;
	/**
     * Return whether Login succedes, thereby evaluates the TL_CONFIG settings.
     * @return boolean
     */
	protected function login() {
		if($this->yt) {return true;}
		if(strlen($GLOBALS['TL_CONFIG']['mayt_developerKey']) > 0 &&
				 strlen($GLOBALS['TL_CONFIG']['mayt_clientId']) > 0 &&
				 strlen($GLOBALS['TL_CONFIG']['mayt_accountLogin']) > 0 && 
				 strlen($GLOBALS['TL_CONFIG']['mayt_accountPass']) > 0) {

			set_include_path(get_include_path() . PATH_SEPARATOR . 
						TL_ROOT.'/system/modules/ma_youtube_api_connector/zend_gdata/library/');

						
			require_once('Zend/Loader.php');
            require_once('Zend/Version.php');
            Zend_Loader::loadClass('Zend_Uri_Http');
            Zend_Loader::loadClass('Zend_Http_Client_Adapter_Socket');
            Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
			Zend_Loader::loadClass('Zend_Gdata_YouTube');

			try {
				$authenticationURL= 'https://www.google.com/youtube/accounts/ClientLogin';
				$httpClient = 
				  Zend_Gdata_ClientLogin::getHttpClient(
            		  $username = $GLOBALS['TL_CONFIG']['mayt_accountLogin'],
            		  $password = $GLOBALS['TL_CONFIG']['mayt_accountPass'],
            		  $service = 'youtube',
            		  $client = null,
            		  $source = 'Typolight', 
            		  $loginToken = null,
            		  $loginCaptcha = null,
            		  $authenticationURL
            		);
            		
            	$httpClient->setConfig(array('timeout' => 30));
            	
            	$developerKey = $GLOBALS['TL_CONFIG']['mayt_developerKey'];
				$applicationId = 'Must Art Youtube API Connector, Typolight';
				$clientId = $GLOBALS['TL_CONFIG']['mayt_clientId'];
			
        	    $this->yt = new Zend_Gdata_YouTube($httpClient, $applicationId, 
        	    										$clientId, $developerKey);
            } catch (Exception $e) {
            	return false;
            }
            $this->yt->setMajorProtocolVersion(2);

            return true;
		}
		return false;
	}
	/**
     * Wrapper for update()
     */
	public function initUpdate($dc) {
		if($this->login()) {
			$this->update();
		}
	}
	/**
     * Updates the Database based on the Youtube set Update-Date, no delete till now!
     */
	public function update() {
		if($this->login()) {
			$this->import('Database', 'Database');

			$dbContent = $this->Database->prepare('SELECT ytId, tstamp, id FROM tl_mayac_videos')->execute()->fetchAllAssoc();
			$videos = $this->yt->getuserUploads($GLOBALS['TL_CONFIG']['mayt_accountLogin']);	
			foreach($videos as $video) {
					$isInDb = false; $isUpToDate = true;
					foreach($dbContent as $dbIndex => $dbVideo) {
						if($dbVideo['ytId'] == 	$video->getVideoId()) {
							$isInDb = true;
							$dbContent[$dbIndex]['found'] = true;
							if($dbVideo['tstamp'] < $this->tstamptotime($video->getUpdated())) {
								$isUpToDate = false;
								
							}
							break;
						}
					}
					//Insert new Videos
					if(!$isInDb) {
						$status = $this->getVideoState($video);
						$this->Database->prepare('INSERT INTO tl_mayac_videos (`id`,`tstamp`, `ytId`, `userId`, `title`,`description`,`tags`,`category`,`private`,`status`,`reason`,`thumbUrl` ) VALUES (\'\',  CURRENT_TIMESTAMP, ?, ?, ?, ?, ?,?, ?, ?, ?, ?)')->execute(
								$video->getVideoId(),
								0,
								$video->getVideoTitle(),
								$video->getVideoDescription(),
								serialize($video->getVideoTags()),
								$video->getVideoCategory(),
								$video->isVideoPrivate()?'1':'',
								$status['name'],
								$status['reasonCode'],
								$this->getThumbnailsForDB($video)
						);
					}
					//update changed Videos
					if($isInDb && !$isUpToDate) {
						$status = $this->getVideoState($video);
						$this->Database->prepare('UPDATE tl_mayac_videos SET tstamp=?,title=?, description=?, tags=?, category=?, private=?, status=?, reason=?, thumbUrl=? WHERE ytId =?')->execute(
							$this->tstamptotime($video->getUpdated()),
							$video->getVideoTitle(),
							$video->getVideoDescription(),
							serialize($video->getVideoTags()),
							$video->getVideoCategory(),
							$video->isVideoPrivate()?'1':'',
							$status['name'],
							$status['reasonCode'],
							$this->getThumbnailsForDb($video),
							$video->getVideoId()
						
						);
					}
			}
			//remove deleted Videos
			foreach($dbContent as $dbVideo) {
				if(!$dbVideo['found'] && strlen($dbVideo['ytId']) > 1) {
					$this->Database->prepare('DELETE FROM tl_mayac_videos WHERE id =?')->execute($dbVideo['id']);
				}
				
			}
			
		}
	}
	/**
     * Not fully implemented
     */
 /*
	public function getAllVideos($blnUpdate = false) {
		if($this->login()) {
			if($blnUpdate) {$this->update();}
			$this->import('Database', 'Database');
			$ids = $this->Database->prepare('SELECT ytId FROM tl_mayac_videos')->execute();
			if($ids->numRows) {
				while($ids->next()) {
					try {
						$videoEntry = $this->yt->getVideoEntry($ids->ytId);
					
						$this->printVideoEntry($videoEntry);
					} catch (Exception $e) {
						//echo $e;
					}
				}
			}
		}
	}
*/
	/**
     * readys a new VideoEntry and retursn token information for modules to generate a upload Form
     * @param string $strTitle
	 * @param string $strTags
	 * @param string $strDescription
	 * @param string $strCategory
	 * @param boolean $blnPrivate
     * @return array
     */
	public function getUploadUrlAndToken($strTitle, $strTags, $strDescription, $strCategory, $blnPrivate) {
		if($this->login()) {

			$myVideoEntry = new Zend_Gdata_YouTube_VideoEntry();

			$myVideoEntry->setVideoTitle($strTitle);
			$myVideoEntry->setVideoDescription($strDescription);
			//do we need to validate the category? If so, how?
			$myVideoEntry->setVideoCategory($strCategory);

			$myVideoEntry->SetVideoTags($strTags);
			if($blnPrivate) {
				$myVideoEntry->setVideoPrivate();
			}	

			$tokenHandlerUrl = 'http://gdata.youtube.com/action/GetUploadToken';
			$tokenArray = $this->yt->getFormUploadToken($myVideoEntry, $tokenHandlerUrl);

			return array('url' => $tokenArray['url'], 'token' => $tokenArray['token']);
		} else {return false;}
	}
	//Public connection
	//evtl own subclass??
	public function getUsersVideos($userId, $arrAdditionalFields) {
		return $this->Database->prepare('SELECT ytId'.(is_array($arrAdditionalFields)?', '.implode(', ', $arrAdditionalFields):'').' FROM tl_mayac_videos WHERE userId=? AND status=? AND ytId!=?')->execute($userId, 0, '')->fetchAllAssoc();
	}
	public function delete($dbId) {
		if($this->login()) {	
			$id = $this->Database->prepare('SELECT ytId FROM tl_mayac_videos WHERE id = ?')->Limit(1)->execute($dbId)->fetchAssoc();
			$entry = $this->yt->getVideoEntry($id['ytId'], null, true);
			$this->yt->delete($entry);
			return true;
		}
		return false;
	}
	public function toggleVisibility($blnSetPrivate, $dbId, $ytId=false) {
		if($this->login()) {
			if(!$ytId) {
				$ytId = $this->Database->prepare('SELECT ytId FROM tl_mayac_videos WHERE id=?')->execute($fbId)->row();
				$ytId = $ytId['ytId'];
			}
			$entry = $this->yt->getVideoEntry($ytId, null, true);
			if(!$blnSetPrivate) { 
				$entry->setVideoPublic();
//				$row['private'] = false;
			} else {
				$entry->setVideoPrivate();
//				$row['private'] = true;
			}
			$this->yt->updateEntry($entry, $entry->getEditLink()->getHref());

			$this->Database->prepare("UPDATE tl_mayac_videos SET private='" . ($blnSetPrivate ? 1 : '') . "' WHERE id=?")
						   ->execute($dbId);
			return true;	   
		}
		return false;
	}
	public function updateEntry($dbId, $strTitle, $strTags, $strDescription, $strCategory, $blnPrivate, $updateDB = false)	{
		if($this->login()) {	
			$result = $this->Database->prepare('SELECT * FROM tl_mayac_videos WHERE id = ?')->execute($dbId)->row();
			if(!strlen($result['ytId'])) {return false;}
			$entry = $this->yt->getVideoEntry($result['ytId'], null, true);
			$entry->setVideoDescription($strDescription);
			$entry->setVideoTitle($strTitle);
			$entry->setVideoTags(deserialize($strTags));
			$entry->setVideoCategory($strCategory);
			if(!$blnPrivate) { 
				$entry->setVideoPublic();
			} else {
				$entry->setVideoPrivate();
			}
			
			$this->yt->updateEntry($entry, $entry->getEditLink()->getHref());
			return true;
		}
		return false;

	}
	//DCA functions
	/**
     * delete a video entry DB + Youtube
     * @param DataContainer $dc 
     */
	public function deleteByDc($dc) {
		$this->delete($dc->id);
	}
	/**
     * toggle the visibility of a videoentry DB + Youtube
     * @param array $row
	 * @param string $href
	 * @param string $label
	 * @param string $title
	 * @param string $icon
	 * @param string $attributes
	 * @return string
     */
	public function toggleIcon($row, $href, $label, $title, $icon, $attributes)
	{
		if (strlen($this->Input->get('tid')) && $this->Input->get('tid') == $row['id'])
		{
			$blnSetPrivate = strlen($this->Input->get('state'))?false:true;
			$row['private'] = $this->toggleVidibility($blnSetPrivate, $$this->Input->get('tid'), $row['ytId']) ? 
															$blnSetPrivate : !$blnSetPrivate;
						   

		}

		$href .= '&amp;tid='.$row['id'].'&amp;state='.$row['private'];

		if ($row['private'])
		{
			$icon = 'invisible.gif';
		}		

		return '<a href="'.$this->addToUrl($href.'&amp;id='.$this->Input->get('id')).'" title="'.specialchars($title).'"'.$attributes.'>'.$this->generateImage($icon, $label).'</a> ';
	}
	/**
     * generate Label for DCA Output
     * @param array $row
	 * @param string $label
	 * @return string
     */
	public function listView($row, $label) {
		$image = deserialize($row['thumbUrl'], true); 
		$image = $image[0]['url'];
		$status = '';
		if($row['status']) {
			$status = '<span style="color: red;" >'.$row['status'].' --- '.$row['reason'].'</span>';
		} elseif(strlen($row['ytId'])) {
			$status = '<span style="color: green;" >online</span>';
		} else {
			$status = '<span style="color: yellow;" >kein Video Hochgeladen</span>';
		}
		
		return '<img style="float:left; margin-right:0.3em;" src="'.$image.'" alt="'.$row['title'].'" /> <div><b>Name: </b>'.$row['title'].'</div><div style="background-color:lightgray;"><b>Status: </b>'.$status.'</div>';
	
	}
	/**
     * update Youtube Entry
     * @param DataContainer $dc
     */
	public function submit($dc) {
		if($this->login()) {	
			$result = $this->Database->prepare('SELECT * FROM tl_mayac_videos WHERE id = ?')->execute($dc->id)->row();
			if(!strlen($result['ytId'])) {return;}
			$entry = $this->yt->getVideoEntry($result['ytId'], null, true);
			$entry->setVideoDescription($result['description']);
			$entry->setVideoTitle($result['title']);
			$entry->setVideoTags(deserialize($result['tags']));
			$entry->setVideoCategory($result['category']);
			if($result['private'] != 1) { 
				$entry->setVideoPublic();
			} else {
				$entry->setVideoPrivate();
			}
			
			$this->yt->updateEntry($entry, $entry->getEditLink()->getHref());
			
		
		}
	
	}
	/**
     * Outputs Video-Stats in Detail View
     * @param DataContainer $dc 
     * @return string
     */
	public function videoCallback($dc) {
		$result = $this->Database->prepare('SELECT ytId, status, reason, title, description, category, tags FROM tl_mayac_videos WHERE id = ?')->Limit(1)->execute($dc->id)->row();
		
		if(strlen($result['ytId']) && !$result['status']) {
			return '<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/'.$result['ytId'].'&hl=de_DE&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/'.$result['ytId'].'&hl=de_DE&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object>';
			
		} elseif($result['status']){
			return '<div>'.$result['status'].'</div><div>'.$result['reason'].'</div>';
		}elseif(strlen($result['title']) && strlen($result['description']) 
									&& strlen($result['tags']) && strlen($result['category'])) {
			
			return '<iframe frameborder="0" src="system/modules/ma_youtube_api_connector/BackendMAYoutubeUserUpload.php?currentId='.$dc->id.'" width="90%" height="100" name="yt_upload"><p>Your Browser can\'t handel iFrames</p> </iframe>';
		}
		
		else {
			return $GLOBALS['TL_LANG'][''];
		}
	}
	//little Helper methods in no particular Order
	/**
     * get Thumbnails, implemented if it is needed to dave only one
     * @param Zend_Gdata_VideoEntry $videoEntry
     * @return array
     */
	protected function getThumbnailsForDb($videoEntry) {
		$videoThumbnails = $videoEntry->getVideoThumbnails();
		return $videoThumbnails;
	}
	//Bug Bypass for Video State Object in YTv2 environment
	/**
     * Get the Status of the Viedeo, allways!
     * @param Zend_Gdata_VideoEntry $newVideoEntry
     * @return array
     */
	protected function getVideoState($newVideoEntry) {
  		$extensionElements = $newVideoEntry->getExtensionElements();

		foreach($extensionElements as $extensionElement) {

    	// find the app:control element
    		if ($extensionElement->rootElement == 'control') {
      			$innerExtensionElements = $extensionElement->getExtensionElements();
		    	foreach($innerExtensionElements as $element) {

        			// find the yt:state element
        			if ($element->rootElement == 'state') {
          				$extensionAttributes = $element->getExtensionAttributes();
          					if (array_key_exists('name', $extensionAttributes)) {
            					return array('name' =>$extensionAttributes['name']['value'], 
 					           					'reasonCode' =>strlen($extensionAttributes['reasonCode']['value'])?$extensionAttributes['reasonCode']['value']:0,
            									'helpUrl' =>$extensionAttributes['helpUrl']['value']);
          					}
        			}
      			}
    		}
  		}
  		return array('name' => 0, 'reasonCode' => 0, 'helpUrl' => 0);

	} 
	/**
     * options_callback to get all currently active videos
     * @return array
     */
	public function getVideosForOptions() {
		$dbVideos = $this->Database->prepare('SELECT title, ytId FROM tl_mayac_videos WHERE status=? AND private!=? ORDER BY title')->execute(0,1)->fetchAllAssoc();
		$out = array();
		//print_r($dbVideos);
		foreach($dbVideos as $dbVideo) {
			if(strlen($dbVideo['ytId']) > 1) {
				$out[$dbVideo['ytId']] = $dbVideo['title'];
			}
		}
		//print_r($out);
		return $out;
		
	}
	/**
     * save_callback to match a properitary xxxApi field with the field xxx, so that CE's and Modules can load correctly
     * @param string $value 
     * @param DataContainer $dc 
     * @return string
     */
	public function matchFields($value, $dc) {
		
		$newField = substr($dc->field, 0 , strlen($dc->field)-3);
		
		$this->Database->prepare('UPDATE '.$dc->table.' SET '.$newField.'=? WHERE id=?')->execute($value, $dc->id);
		return $value;
	}	
	/**
     * convert the ISO 8601 Date to Unix Timestamp
     * @param string $tstamp 
     * @return string
     */
	protected function tstamptotime($tstamp) {
        // converts ISODATE to unix date
        // 1984-09-01T14:21:31Z
       	sscanf($tstamp,"%u-%u-%uT%u:%u:%uZ",$year,$month,$day,
        $hour,$min,$sec);
        $newtstamp=mktime($hour,$min,$sec,$month,$day,$year);
        return $newtstamp;
    }      
	//Category Functions based on XML and Config-File	
	/**
     * Simple XML to load the categories file from Youtube And Store them to the global config
     * @return string
     */
	public function getListOfCategories() {
		$out = array();
		$objRequest = new Request();
		$objRequest->send($GLOBALS['TL_CONFIG']['mayt_configUrl'].'?hl='.$GLOBALS['TL_CONFIG']['mayt_configLang']);
		if($objRequest->hasError()) {
			$objRequest = new Request();
			$objRequest->send($GLOBALS['TL_CONFIG']['mayt_configUrl']);
			if($objRequest->hasError()) {
				return $out;
			}
		}

		$cxml = simplexml_load_string($objRequest->response);
		if(!is_object($cxml)) {
			return $out;
		}
		$cxml->registerXPathNamespace('atom', 'http://www.w3.org/2005/Atom');
	    $categories = $cxml->xpath('//atom:category');

		foreach($categories as $cat) {
			if(!isset($cat->deprecated))
				$out[(string)$cat['term']] = specialchars((string)$cat['label']);

		}
		if(strlen($GLOBALS['TL_CONFIG']['mayt_possibleCategories'])) {
			$this->Config->update('$GLOBALS[\'TL_CONFIG\'][\'mayt_possibleCategories\']', serialize($out));
		} else {
			$this->Config->add('$GLOBALS[\'TL_CONFIG\'][\'mayt_possibleCategories\']', serialize($out));
		}

		return $out;
		
	}
	/**
     * generate Array for Selct based checkboxWizard output
     * @param string $strSelected
     * @param string $strValue
     * @return array
     */	
	public function getCategorys($strSelected, $strValue) {
		$arrSelected = deserialize($strSelected);
		$arrPossible = deserialize($GLOBALS['TL_CONFIG']['mayt_possibleCategories']);
		$out = array();
		
		foreach($arrSelected as $selected) {
			$out[$selected] = $arrPossible[$selected];
		}
		if(strlen($strValue) && !in_array($strValue, $arrSelected)) {
			$out[$strValue] = $arrPossible[$strValue];
		}
		
		return $out;
	
	}	
	/**
     * wrapper for getCategory for global Output to the DCA
     * @param DataContainer $dc
     * @return array
     */	
	public function getGlobalCategories($dc) {
		return $this->getCategorys($GLOBALS['TL_CONFIG']['mayt_categorys'], $dc->value);
	}
	
	
	//Test purpos only!
	protected function printVideoEntry($videoEntry) 
	{
		//print_r($this->getVideoState($videoEntry));
		//$ext = $videoEntry->getExtensionElements();
		//print_r($ext);
		
		// the videoEntry object contains many helper functions
		// that access the underlying mediaGroup object
		echo 'Video: ' . $videoEntry->getVideoTitle() . "\n";
		echo 'Video ID: ' . $videoEntry->getVideoId() . "\n";
		echo 'Updated: ' . $videoEntry->getUpdated() . "\n";
		echo 'Description: ' . $videoEntry->getVideoDescription() . "\n";
		echo 'Category: ' . $videoEntry->getVideoCategory() . "\n";
		echo 'Tags: ' . implode(", ", $videoEntry->getVideoTags()) . "\n";
		echo 'Watch page: ' . $videoEntry->getVideoWatchPageUrl() . "\n";
		echo 'Flash Player Url: ' . $videoEntry->getFlashPlayerUrl() . "\n";
		echo 'Duration: ' . $videoEntry->getVideoDuration() . "\n";
		echo 'View count: ' . $videoEntry->getVideoViewCount() . "\n";
		echo 'Rating: ' . $videoEntry->getVideoRatingInfo() . "\n";
		echo 'Geo Location: ' . $videoEntry->getVideoGeoLocation() . "\n";
		echo 'Recorded on: ' . $videoEntry->getVideoRecorded() . "\n";
	
		// see the paragraph above this function for more information on the 
		// 'mediaGroup' object. in the following code, we use the mediaGroup
		// object directly to retrieve its 'Mobile RSTP link' child
		foreach ($videoEntry->mediaGroup->content as $content) {
			if ($content->type === "video/3gpp") {
			echo 'Mobile RTSP link: ' . $content->url . "\n";
			}
		}
  
		echo "Thumbnails:\n";
		$videoThumbnails = $videoEntry->getVideoThumbnails();

		foreach($videoThumbnails as $i => $videoThumbnail) {
			echo $i.'  ---   ';
			echo $videoThumbnail['time'] . ' - ' . $videoThumbnail['url'];
			echo ' height=' . $videoThumbnail['height'];
			echo ' width=' . $videoThumbnail['width'] . "\n";
			//echo '<img src="'.$videoThumbnail['url'].'" />';
		}
		//echo 'state='.$this->getVideoState($videoEntry)."\n";
		
		$state = $videoEntry->getVideoState();
		if(null != $state) {
			echo 'state='.print_r($videoEntry->getVideoState()->getReasonCode())."\n";
		}	
	}
}
?>